﻿using System;
using System.Drawing;
using System.Windows.Forms;

namespace IA2MazeSolver
{
    public class Maze
    {
        public int[][] Data;

        public int Height;
        public int Width;

        public int DrawHeight;
        public int DrawWidth;

        public Point StartPoint;
        public Point EndPoint;

        public Maze()
        {
            this.StartPoint = new Point(0, 9);
            this.EndPoint = new Point(9, 0);

            this.Height = 10;
            this.Width = 10;

            this.DrawHeight = 21;
            this.DrawWidth = 21;

            this.Data = new int[21][];
            this.Data[00] = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
            this.Data[01] = new int[] { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 };
            this.Data[02] = new int[] { 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0 };
            this.Data[03] = new int[] { 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0 };
            this.Data[04] = new int[] { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0 };
            this.Data[05] = new int[] { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0 };
            this.Data[06] = new int[] { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0 };
            this.Data[07] = new int[] { 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 };
            this.Data[08] = new int[] { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0 };
            this.Data[09] = new int[] { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 };
            this.Data[10] = new int[] { 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
            this.Data[11] = new int[] { 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 };
            this.Data[12] = new int[] { 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
            this.Data[13] = new int[] { 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0 };
            this.Data[14] = new int[] { 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0 };
            this.Data[15] = new int[] { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0 };
            this.Data[16] = new int[] { 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0 };
            this.Data[17] = new int[] { 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0 };
            this.Data[18] = new int[] { 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
            this.Data[19] = new int[] { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 };
            this.Data[20] = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        }

        public void RenderTo(Panel painel)
        {
            byte[] caminho = new byte[0];
            this.RenderTo(painel, caminho);
        }

        public void RenderTo(Panel painel, byte[] caminho)
        {
            painel.Controls.Clear();

            double painelHeight = painel.Height;
            double painelWidth = painel.Width;

            int labelHeight = (int)Math.Floor(painelHeight / this.DrawHeight);
            int labelWidth = (int)Math.Floor(painelWidth / this.DrawWidth);

            /*
             * Renderizo as paredes
             */
            for (int j = 0; j < this.DrawHeight; j++)
            {
                for (int i = 0; i < this.DrawWidth; i++)
                {
                    if (this.Data[j][i] <= 0)
                    {
                        int x = i * labelWidth;
                        int y = j * labelHeight;
                        Label label = new Label();
                        label.AutoSize = false;
                        label.Size = new Size(labelWidth, labelHeight);
                        label.BackColor = Color.LawnGreen;
                        label.Location = new Point(x, y);/*
                        label.Font = new Font("Arial", 6);
                        label.Text = i + ";" + j;*/
                        painel.Controls.Add(label);
                    }
                }
            }

            /*
             * Renderizo o caminho
             */
            //Inicio!
            if (caminho.Length >= 2)
            {
                //this.DrawLine(painel, new Point(this.StartPoint.X - 1, this.StartPoint.Y), new Direcao(0, 0), labelWidth, labelWidth);

                //Point ParouEm = this.DrawLine(painel, this.StartPoint, new Direcao(caminho[0], caminho[1]), labelWidth, labelWidth);
                //Point ParouEm = this.DrawLine(painel, new Point(this.StartPoint.X - 1, this.StartPoint.Y), new Direcao(0, 0), labelWidth, labelWidth);

                Point ParouEm = this.DrawLine(painel, new Point(this.StartPoint.X - 1, this.StartPoint.Y), new Direcao(caminho[0], caminho[1]), labelWidth, labelWidth);

                //Todo o resto
                for (int k = 2; k < caminho.Length; k += 2)
                {
                    ParouEm = this.DrawLine(painel, ParouEm, new Direcao(caminho[k], caminho[k + 1]), labelWidth, labelWidth);
                }

                if (ParouEm.X == this.EndPoint.X)
                {
                    //this.DrawLine(painel, this.EndPoint, new Direcao(0, 0), labelWidth, labelWidth);
                }
            }
        }

        private Point DrawLine(Panel painel, Point FromMatrix, Direcao Sentido, int LabelWidth, int LabelHeight)
        {
            Point To = new Point(0, 0);

            Point From = this.ToMeasureDraw(FromMatrix);

            int density = 0;
            if (LabelWidth < LabelHeight)
            {
                density = (int)Math.Floor(LabelWidth / 5f);
            }
            else
            {
                density = (int)Math.Floor(LabelHeight / 5f);
            }

            int margemH = (int)Math.Floor(LabelWidth / 2f) - (int)Math.Floor(density / 2f);
            int margemV = (int)Math.Floor(LabelHeight / 2f) - (int)Math.Floor(density / 2f);

            Label label = new Label();
            label.AutoSize = false;
            label.BackColor = Color.Red;

            //Leste
            if (Sentido.Equals(Direcao.Leste))
            {
                label.Size = new Size((LabelWidth * 2), density);

                int pX = (From.X * LabelWidth) + margemH;
                int pY = (From.Y * LabelHeight) + margemV;

                label.Location = new Point(pX, pY);

                To = new Point(FromMatrix.X + 1, FromMatrix.Y);
            }

            //Norte
            if (Sentido.Equals(Direcao.Norte))
            {
                label.Size = new Size(density, ( LabelHeight * 2 ));

                int pX = (From.X * LabelWidth) + margemH;
                int pY = (From.Y * LabelHeight) - LabelHeight - margemV;

                label.Location = new Point(pX, pY);

                To = new Point(FromMatrix.X, FromMatrix.Y - 1);
            }

            //Oeste
            if (Sentido.Equals(Direcao.Oeste))
            {
                label.Size = new Size((LabelWidth * 2), density);

                int pX = (From.X * LabelWidth) - LabelWidth - margemH;
                int pY = (From.Y * LabelHeight) + margemV;

                label.Location = new Point(pX, pY);

                To = new Point(FromMatrix.X - 1, FromMatrix.Y);
            }

            //Sul
            if (Sentido.Equals(Direcao.Sul))
            {
                label.Size = new Size(density, (LabelHeight * 2));

                int pX = (From.X * LabelWidth) + margemH;
                int pY = (From.Y * LabelHeight) + margemV;

                label.Location = new Point(pX, pY);

                To = new Point(FromMatrix.X, FromMatrix.Y + 1);
            }

            painel.Controls.Add(label);
            painel.Controls.SetChildIndex(label, 1);

            return To;
        }

        public Point ToMeasureDraw(Point matrizPoint)
        {
            int x = ( matrizPoint.X * 2 ) + 1;
            int y = ( matrizPoint.Y * 2 ) + 1;

            return new Point(x, y);
        }

        public int GetDadoFrom(Point p)
        {
            if (p.X < 0 || p.X >= this.DrawWidth || p.Y < 0 || p.X >= this.DrawHeight)
            {
                return -1;
            }
            else
            {
                return this.Data[p.Y][p.X];
            }
        }
    }
}
